﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using FolderLib;
using FtpLib;

namespace FolderSyncLib
{
    public class FolderSync
    {
        public List<string> _fileList = new List<string>();
        
        
        private EventLog _eventLog1;

        private string LOCAL_DEFAULTFOLDER; //Thư mục mặc định ở local
        private readonly string FTP_DEFAULTFOLDER = "/report/results"; //Thư mục mặc định trên server
        private string _ftpserver;
        private string _username;
        private string _password;

        public bool _isSyncStatus = true; //Cho biết trạng thái đang đồng bộ hay đồng bộ xong
        public FolderSync(string folder, string ftpserver, string username, string password, EventLog eventLog)
        {
            _isSyncStatus = true;
            _ftpserver = ftpserver;
            _username = username;
            _password = password;
            LOCAL_DEFAULTFOLDER = folder;
            _eventLog1 = eventLog;
        }

        /// <summary>
        /// Hàm khởi tạo FileSystemWatcher
        /// </summary>
        public void StartFileSystemWatcher()
        {
            try
            {
                FileProcessor.CreateDefaultDirectories(LOCAL_DEFAULTFOLDER);
                FileSystemWatcher watch = new FileSystemWatcher();
                watch.Path = LOCAL_DEFAULTFOLDER;
                //watch.Changed += new FileSystemEventHandler(OnChanged);
                watch.Created += new FileSystemEventHandler(OnCreated);
                watch.Deleted += new FileSystemEventHandler(OnDeleted);
                watch.Renamed += new RenamedEventHandler(OnRenamed);
                watch.EnableRaisingEvents = true;
                watch.IncludeSubdirectories = true;
                WriteLog(string.Format("Start Watching Folder {0}", LOCAL_DEFAULTFOLDER), EventLogEntryType.Information);
            }
            catch (Exception ex)
            {
                WriteLog(string.Format("Error Watching Folder {0}: {1}", LOCAL_DEFAULTFOLDER, ex.Message), EventLogEntryType.Information);
            }
        }

        ////-------------------------------------------------- 
        //private void OnChanged(object source, FileSystemEventArgs e)
        //{
        //    // Specify what is done when a file is changed, created, or deleted. 
        //    string dir = LOCAL_DEFAULTFOLDER + "\\" + e.Name;
        //    _eventLog1.WriteEntry(string.Format("Changed Type: {0};\n File: {1};\n FullPath: {2}", e.ChangeType, e.Name, e.FullPath));
        //}


        public void UploadProcessor(string fullPath)
        {
            try
            {
                FileProcessor.CreateDefaultDirectories(LOCAL_DEFAULTFOLDER);
                //Specify what is done when a file is changed, created, or deleted. 
                if (FileProcessor.IsFolderPath(fullPath))
                {
                    string companyPathFormat = "\\COMPANY\\";
                    string personalPathFormat = "\\PERSONAL\\";
                    if (fullPath.Contains(companyPathFormat) || fullPath.Contains(personalPathFormat)) //Nếu đường dẫn theo định dạng Company
                    {
                        StartSyncFolder(fullPath);
                    }
                }
            }
            catch (Exception ex)
            {
                _isSyncStatus = true;
                WriteLog(string.Format("Error: {0} {1}", ex.Message, ex.StackTrace), EventLogEntryType.Error);
            }


            //try
            //{
            //    if (_isSyncStatus)
            //    {
            //        _isSyncStatus = false;
            //        StartSyncFolder();
            //        _isSyncStatus = true;
            //    }
            //}
            //catch (Exception ex)
            //{
            //    _isSyncStatus = true;
            //    WriteLog(string.Format("Error: {0} {1}", ex.Message, ex.StackTrace), EventLogEntryType.Error);
            //}
        }

        public List<string> uploadFiles = new List<string>();
        public void Upload2(string fullPath)
        {
            try
            {
                //Nếu là file thì add vào list
                if (!FileProcessor.IsFolderPath(fullPath))
                {
                    uploadFiles.Add(fullPath);
                }
            }
            catch (Exception ex)
            {
                _isSyncStatus = true;
                WriteLog(string.Format("Error: {0} {1}", ex.Message, ex.StackTrace), EventLogEntryType.Error);
            }


           
        }
        /// <summary>
        /// Sự kiện đồng bộ xảy ra khi thêm mới file, folder
        /// </summary>
        /// <param name="source"></param>
        /// <param name="e"></param>
        private void OnCreated(object source, FileSystemEventArgs e)
        {
            UploadProcessor(e.FullPath);
        }

        //-------------------------------------------------- 
        private void OnDeleted(object source, FileSystemEventArgs e)
        {
            // Specify what is done when a file is changed, created, or deleted. 
            string dir = LOCAL_DEFAULTFOLDER + "\\" + e.Name;

            //WriteLog(string.Format("Delete {0}", e.Name), EventLogEntryType.Information);
        }

        // ---------------------------------------------------------------------------------- 
        private void OnRenamed(object source, RenamedEventArgs e)
        {
            // Specify what is done when a file is renamed. 
            string dir = LOCAL_DEFAULTFOLDER + "\\" + e.Name;
            
            //WriteLog(string.Format("Rename \"{0}\" to \"{1}\";", e.OldName, e.Name), EventLogEntryType.Information);
        }

        public string LocalPathToFTPPath(string localPath)
        {
            return FTP_DEFAULTFOLDER + localPath.Replace(LOCAL_DEFAULTFOLDER, "").Replace("\\", "/");

        }

        public string FTPPathToLocalPath(string ftpPath)
        {
            return LOCAL_DEFAULTFOLDER + ftpPath.Replace(FTP_DEFAULTFOLDER, "").Replace("/", "\\");

        }

        private void UploadFolder(FtpConnection _ftp, string localFolder)
        {
            string[] files = Directory.GetFiles(localFolder);
            //Nếu thư mục có nhiều hơn 1 file thì upload
            if (files.Length > 1)
            {
                Dictionary<string, string> fileList = new Dictionary<string, string>();
                foreach (string file in files)
                {
                    fileList.Add(Path.GetFileName(file), file);
                }

                //Kiểm tra những file này đã up lên server chưa, nếu up rồi thì ko up lại
                string ftpFolder = LocalPathToFTPPath(localFolder);
                if (_ftp.DirectoryExists(ftpFolder))
                {
                    //Lấy những file tồn tại trên FTP
                    _ftp.SetCurrentDirectory(ftpFolder);
                    FtpDirectoryInfo ftpDirectory = _ftp.GetCurrentDirectoryInfo();
                    FtpFileInfo[] ftpFiles = ftpDirectory.GetFiles();
                    foreach (FtpFileInfo ftpFile in ftpFiles)
                    {
                        //Nếu tồn tại rồi thì bỏ ra khỏi List
                        if (fileList.ContainsKey(ftpFile.Name))
                            fileList.Remove(ftpFile.Name);
                    }
                }

                //Upload những file trong List
                foreach (KeyValuePair<string, string> item in fileList)
                {
                    UploadFile(_ftp, item.Value);
                }
            }
            else
            {
                FindFolder(_ftp, localFolder);
            }
        }

        /// <summary>
        /// Vòng lặp tìm folder, nếu folder đó chứa nhiều file thì upload
        /// </summary>
        /// <param name="folderPaths"></param>
        private void FindFolder(FtpConnection _ftp, string folderPaths)
        {
            string[] files = Directory.GetFiles(folderPaths);
            //Nếu folder này có nhiều files và folder là Company hoặc Pthì upload
            if (files.Length > 0)
            {
                //Kiểm tra đường dẫn thư mục có hợp lệ không
                string result = FileProcessor.ValidatingFolderPath(folderPaths);
                if (result != "") //Nếu không hợp lệ thì báo lỗi và bỏ qua upload file
                {
                    WriteLog(result, EventLogEntryType.Warning);
                    return;
                }

                UploadFolder(_ftp, folderPaths);
            }
            else
            {
                string[] childfolderPaths = Directory.GetDirectories(folderPaths);

                foreach (var localFolder in childfolderPaths)
                {
                    //Kiểm tra đường dẫn thư mục có hợp lệ không
                    string result = FileProcessor.ValidatingFolderPath(localFolder);
                    if (result != "") //Nếu không hợp lệ thì báo lỗi và bỏ qua upload file
                    {
                        WriteLog(result, EventLogEntryType.Warning);
                        continue;
                    }

                    UploadFolder(_ftp, localFolder);
                }    
            }

            
        }


        //public int _NumOfFiles = 0;
        //public string _CurrFile = "";
        /// <summary>
        /// Hàm bắt đầu thực hiện đồng bộ file của Folder
        /// </summary>
        public void StartSyncFolder(string rootFolder)
        {
            FtpConnection _ftp = new FtpConnection(_ftpserver, _username, _password);
            try
            {
                _ftp.Open(); /* Open the FTP connection */
                _ftp.Login(); /* Login using previously provided credentials */
                //WriteLog("Connect FTP successful!", EventLogEntryType.Information);
                int count = Directory.GetFiles(rootFolder, "*.*", SearchOption.AllDirectories).Length;
                bool isUploadComplete = false;
                while (!isUploadComplete) //Chưa load hết file thì tiếp tục sync
                {
                    //Bắt đầu thực hiện đồng bộ
                    FindFolder(_ftp, rootFolder);

                    //Kiểm tra xem có file mới thêm vào sau khi upload lần gần nhất
                    int currCount = Directory.GetFiles(rootFolder, "*.*", SearchOption.AllDirectories).Length;
                    if (count != currCount)
                    {
                        count = currCount;
                    }
                    else
                        isUploadComplete = true;
                }
            }
            catch (Exception ex)
            {
                WriteLog(string.Format("Synchronize error: {0} {1}", ex.Message, ex.StackTrace), EventLogEntryType.Error);
            }
            finally
            {
                _ftp.Close();    
            }
            

        }

        //public int _NumOfFiles = 0;
        //public string _CurrFile = "";
        /// <summary>
        /// Hàm bắt đầu thực hiện đồng bộ file của Folder
        /// </summary>
        public void StartSyncFolder()
        {
            FtpConnection _ftp = new FtpConnection(_ftpserver, _username, _password);
            try
            {
                _ftp.Open(); /* Open the FTP connection */
                _ftp.Login(); /* Login using previously provided credentials */
                //WriteLog("Connect FTP successful!", EventLogEntryType.Information);
                string rootFolder = LOCAL_DEFAULTFOLDER + "\\" + FileProcessor.CreateCurrentDateFolder();
                int count = Directory.GetFiles(rootFolder, "*.*", SearchOption.AllDirectories).Length;
                bool isUploadComplete = false;
                FileProcessor.CreateDefaultDirectories(LOCAL_DEFAULTFOLDER);
                WriteLog(string.Format("Start Synchronize Folder {0} ", rootFolder), EventLogEntryType.Information);
                while (!isUploadComplete) //Chưa load hết file thì tiếp tục sync
                {
                    //Bắt đầu thực hiện đồng bộ
                    FindFolder(_ftp, rootFolder);

                    //Kiểm tra xem có file mới thêm vào sau khi upload lần gần nhất
                    int currCount = Directory.GetFiles(rootFolder, "*.*", SearchOption.AllDirectories).Length;
                    if (count != currCount)
                    {
                        isUploadComplete = false;
                        count = currCount;
                    }
                    else
                        isUploadComplete = true;
                }
                WriteLog(string.Format("Synchronize Complete!", rootFolder), EventLogEntryType.Information);
            }
            catch (Exception ex)
            {
                WriteLog(string.Format("Synchronize error: {0} {1}", ex.Message, ex.StackTrace), EventLogEntryType.Error);
            }
            finally
            {
                _ftp.Close();
            }


        }

        /// <summary>
        /// Tạo FTP folder ánh xạ với local folder
        /// </summary>
        /// <param name="localFolder"></param>
        /// <returns></returns>
        private string CreateFTPFolder(FtpConnection _ftp, string localFolder)
        {
            string ftpFolder = FTP_DEFAULTFOLDER + localFolder.Replace(LOCAL_DEFAULTFOLDER, "").Replace("\\", "/");
            //Nếu không tồn tại folder ftpFolder thì tạo từng folder một
            if (!_ftp.DirectoryExists(ftpFolder))
            {
                ftpFolder = FTP_DEFAULTFOLDER;
                string[] paths = localFolder.Replace(LOCAL_DEFAULTFOLDER, "").Split(new char[] { '\\' });
                foreach (var s in paths)
                {
                    ftpFolder += s;
                    //Kiểm tra thư mục tồn tại không
                    if (!_ftp.DirectoryExists(ftpFolder))
                    {
                        try
                        {
                            //Nếu không tồn tại thì tạo mới
                            _ftp.CreateDirectory(ftpFolder);
                        }
                        catch (FtpException e)
                        {
                            _ftp.Close();
                            _ftp.Open();
                            _ftp.Login();
                            if (!_ftp.DirectoryExists(ftpFolder))
                                WriteLog(String.Format("FTP Error: {0} {1}", e.ErrorCode, e.Message), EventLogEntryType.Error);
                        }
                    }
                    ftpFolder += "/";
                }
            }
            //ftpFolder = ftpFolder.Substring(0, ftpFolder.Length - 1);
            return ftpFolder;
        }

        public void WriteLog(string content, EventLogEntryType type)
        {
            _eventLog1.WriteEntry(content, type);
        }

        
                
        //public void UploadFileList(FtpConnection _ftp)
        //{
        //    foreach (string file in _fileList)
        //    {
        //        UploadFile(_ftp, file);
        //    }
        //}

        /// <summary>
        /// Upload file bằng FTP
        /// 1. Đọc thư mục theo ngày. Ví dụ: ngày 16-12-2013 thì đặt thư mục là ngày 2013/12/16 (nếu chưa có thì service sẽ tạo thư mục đó)
        /// 2. Service sẽ đọc thông tin thư mục của ngày hôm đó (nếu muốn up bệnh nhân nào thì cứ đưa vào thư mục của ngày hôm đó). 
        ///    Thông tin thư mục bệnh nhân gồm MASO-TEN-TEN_CTY
        /// 3. Với từng thư mục sẽ upload lên server
        /// 4. Người quản trị vào trang web đó chọn thư mục up lên và nhấn lưu vào CSDL đồng thời phát sinh Pass tự động
        /// 5. Chương trình sẽ đọc thư mục đó và lưu vào CSDL theo thông tin thư mục: Mã số - Tên - Tên cty - Pass và đường dẫn thư mục upload, ngày tạo
        /// 6. Kiểm tra đã tồn tại bệnh nhân đó chưa (theo Code và FolderPath). Nếu chưa thì tạo mới, nếu rồi thì thông báo
        /// 7. Chương trình hiển thị ra danh sách bệnh nhân theo thông tin trên và khi chọn bệnh nhân nào thì hiển thị thư mục ảnh của bệnh nhân đó
        /// </summary>
        public void UploadFile(FtpConnection _ftp, string filePath)
        {
            try
            {
                if (Path.GetFileName(filePath) == "Thumbs.db")
                {
                    return;
                }

                //Nếu file cần upload không nằm trong đường dẫn hợp lệ thì không upload
                string result = FileProcessor.ValidatingFilePath(filePath);
                if (result != "")
                {
                    WriteLog(result, EventLogEntryType.Warning);
                    return;
                }


                string fileName = Path.GetFileName(filePath);
                string localFolder = Path.GetDirectoryName(filePath);

                string ftpFolder = CreateFTPFolder(_ftp, localFolder);
                _ftp.SetCurrentDirectory(ftpFolder); /* change current directory */
                string ftpFile = ftpFolder + "/" + fileName;
                //Kiểm tra trên folder ftp đã có file này chưa
                if (!_ftp.FileExists(ftpFile)) /* check that a file exists */
                {
                    try
                    {
                        //Nếu chưa thì upload lên
                        _ftp.PutFile(filePath, fileName);
                        WriteLog(string.Format("Upload Complete {0}!", filePath), EventLogEntryType.SuccessAudit);
                    }
                    catch (FtpException e)
                    {
                        _ftp.Close();
                        _ftp.Open();
                        _ftp.Login();
                        if (!_ftp.FileExists(ftpFile))
                            WriteLog(String.Format("FTP Error: {0} {1}", e.ErrorCode, e.Message),EventLogEntryType.Error);
                    }
                }

            }
            catch (FtpException e)
            {
                WriteLog(String.Format("FTP Error: {0} {1}", e.ErrorCode, e.Message), EventLogEntryType.Error);
            }

        }

        public void SyncRenamedFile(string oldFtpFile, string newFtpFile)
        {
            FtpConnection _ftp;
            _ftp = new FtpConnection(_ftpserver, _username, _password);
            //Kiểm tra trên folder ftp đã có file này chưa
            if (!_ftp.FileExists(oldFtpFile)) /* check that a file exists */
            {
                try
                {
                    _ftp.RenameFile(oldFtpFile, newFtpFile);
                    //Kiểm tra sau khi rename
                    if (_ftp.FileExists(newFtpFile))
                        WriteLog(string.Format("Rename File Complete {0}!", newFtpFile), EventLogEntryType.SuccessAudit);
                }
                catch (FtpException e)
                {
                    _ftp.Close();
                    _ftp.Open();
                    _ftp.Login();
                    if (!_ftp.FileExists(oldFtpFile))
                        WriteLog(String.Format("FTP Error: {0} {1}", e.ErrorCode, e.Message), EventLogEntryType.Error);
                }
            }

            _ftp.Close(); /* Open the FTP connection */
        }

        public void SyncRenamedFolder(string oldFtpPath, string newFtpPath)
        {
            FtpConnection _ftp;
            _ftp = new FtpConnection(_ftpserver, _username, _password);
            //Kiểm tra trên folder ftp đã có file này chưa
            if (!_ftp.DirectoryExists(oldFtpPath)) /* check that a file exists */
            {
                try
                {
                    _ftp.RenameFile(oldFtpPath, newFtpPath);
                    //Kiểm tra sau khi rename
                    if (_ftp.DirectoryExists(newFtpPath))
                        WriteLog(string.Format("Rename Directory Complete {0}!", newFtpPath), EventLogEntryType.SuccessAudit);
                }
                catch (FtpException e)
                {
                    _ftp.Close();
                    _ftp.Open();
                    _ftp.Login();
                    if (!_ftp.DirectoryExists(oldFtpPath))
                        WriteLog(String.Format("FTP Error: {0} {1}", e.ErrorCode, e.Message), EventLogEntryType.Error);
                }
            }

            _ftp.Close(); /* Open the FTP connection */
        }

        /// <summary>
        /// Synchronize renamed file or folder
        /// </summary>
        /// <param name="oldPath"></param>
        /// <param name="newPath"></param>
        public void SyncRename(string oldPath, string newPath)
        {
            FtpConnection _ftp;
            try
            {
                ////Nếu file cần upload không nằm trong đường dẫn hợp lệ thì không upload
                //if (!FileProcessor.ValidatingFilePath(oldPath))
                //{
                //    WriteLog(string.Format("Path {0} is invalid path to synchronize renamed path", oldPath), EventLogEntryType.Warning);
                //    return;
                //}

                if (FileProcessor.IsFolderPath(newPath))
                    return;

                //Nếu file cần upload không nằm trong đường dẫn hợp lệ thì không upload
                string result = FileProcessor.ValidatingFilePath(newPath);
                if (result != "")
                {
                    WriteLog(result, EventLogEntryType.Warning);
                    return;
                }

                _ftp = new FtpConnection(_ftpserver, _username, _password);
                _ftp.Open(); /* Open the FTP connection */
                _ftp.Login(); /* Login using previously provided credentials */

                string oldFtpPath = FTP_DEFAULTFOLDER + oldPath.Replace(LOCAL_DEFAULTFOLDER, "").Replace("\\", "/");
                string newFtpPath = FTP_DEFAULTFOLDER + newPath.Replace(LOCAL_DEFAULTFOLDER, "").Replace("\\", "/");

                //Kiểm tra trên folder ftp đã có file này chưa
                if (!_ftp.FileExists(oldFtpPath)) /* check that a file exists */
                {
                    try
                    {
                        _ftp.RenameFile(oldFtpPath, newFtpPath);
                        if (FileProcessor.IsFolderPath(oldPath))
                        {
                            //Kiểm tra sau khi rename
                            if (_ftp.DirectoryExists(newFtpPath))
                                WriteLog(string.Format("Rename Complete {0}!", newFtpPath), EventLogEntryType.SuccessAudit);
    
                        }
                        else
                        {
                            //Kiểm tra sau khi rename
                            if (_ftp.FileExists(newFtpPath))
                                WriteLog(string.Format("Rename Complete {0}!", newFtpPath), EventLogEntryType.SuccessAudit);
                        }
                        
                    }
                    catch (FtpException e)
                    {
                        _ftp.Close();
                        _ftp.Open();
                        _ftp.Login();
                        if (!_ftp.FileExists(oldFtpPath))
                            WriteLog(String.Format("FTP Error: {0} {1}", e.ErrorCode, e.Message), EventLogEntryType.Error);
                    }
                }

                _ftp.Close(); /* Open the FTP connection */

            }
            catch (FtpException e)
            {
                WriteLog(String.Format("FTP Error: {0} {1}", e.ErrorCode, e.Message), EventLogEntryType.Error);
            }

        }

        /// <summary>
        /// Synchronize delete file or folder
        /// </summary>
        /// <param name="deletedPath"></param>
        public void SyncDelete(string deletedPath)
        {
            FtpConnection _ftp;
            try
            {
                
                
                ////Nếu file cần upload không nằm trong đường dẫn hợp lệ thì không upload
                //if (!FileProcessor.ValidatingFilePath(deletedPath))
                //{
                //    WriteLog(string.Format("Path {0} is invalid path to synchronize deleted path", deletedPath), EventLogEntryType.Warning);
                //    return;
                //}

                
                if (FileProcessor.IsFolderPath(deletedPath))
                    return;

                //Nếu file cần upload không nằm trong đường dẫn hợp lệ thì không upload
                string result = FileProcessor.ValidatingFilePath(deletedPath);
                if (result != "")
                {
                    WriteLog(result, EventLogEntryType.Warning);
                    return;
                }

                _ftp = new FtpConnection(_ftpserver, _username, _password);
                _ftp.Open(); /* Open the FTP connection */
                _ftp.Login(); /* Login using previously provided credentials */

                string deletedFtpPath = FTP_DEFAULTFOLDER + deletedPath.Replace(LOCAL_DEFAULTFOLDER, "").Replace("\\", "/");

                //Kiểm tra trên folder ftp đã có file này chưa
                if (!_ftp.FileExists(deletedFtpPath)) /* check that a file exists */
                {
                    try
                    {
                        if (FileProcessor.IsFolderPath(deletedPath))
                        {
                            _ftp.RemoveDirectory(deletedFtpPath);
                            //Kiểm tra sau khi rename
                            if (_ftp.DirectoryExists(deletedFtpPath))
                                WriteLog(string.Format("Delete directory complete {0}!", deletedFtpPath), EventLogEntryType.SuccessAudit);
                        }

                        else
                        {
                            _ftp.RemoveFile(deletedFtpPath);
                            //Kiểm tra sau khi rename
                            if (_ftp.FileExists(deletedFtpPath))
                                WriteLog(string.Format("Delete file complete {0}!", deletedFtpPath), EventLogEntryType.SuccessAudit);
                        }


                    }
                    catch (FtpException e)
                    {
                        _ftp.Close();
                        _ftp.Open();
                        _ftp.Login();
                        if (FileProcessor.IsFolderPath(deletedPath))
                        {
                            if (_ftp.DirectoryExists(deletedFtpPath))
                                WriteLog(String.Format("FTP Error: {0} {1}", e.ErrorCode, e.Message), EventLogEntryType.Error);
                        }

                        else
                        {
                            //Kiểm tra sau khi rename
                            if (_ftp.FileExists(deletedFtpPath))
                                WriteLog(String.Format("FTP Error: {0} {1}", e.ErrorCode, e.Message), EventLogEntryType.Error);
                        }
                            
                    }
                }

                _ftp.Close(); /* Open the FTP connection */

            }
            catch (FtpException e)
            {
                WriteLog(String.Format("FTP Error: {0} {1}", e.ErrorCode, e.Message), EventLogEntryType.Error);
            }

        }

    }
}
